package com.labofjet.jpa.bean.impl;

import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.springframework.stereotype.Repository;

import com.labofjet.jpa.bean.NativeSQLRepository;

/**
 * 需要使用原生SQL的repository的父类
 * 
 * @author jyzjyz12@163.com
 * 
 */
@Repository
@SuppressWarnings({ "rawtypes", "unchecked" })
public class NativeSQLRepositoryImpl implements NativeSQLRepository {

	@PersistenceContext(name = "entityManager")
	EntityManager entityManager;

	@Override
	public Object querySingleByNamedQuery(String namedQuery, Map<String, Object> paramMap) {
		EntityManager em = getEntityManager();
		Query query = em.createNativeQuery(namedQuery);
		this.initQueryParamters(paramMap, query);
		return query.getSingleResult();
	}

	@Override
	public List queryListByNamedQuery(String namedQuery, Map<String, Object> paramMap) {
		EntityManager em = getEntityManager();
		Query query = em.createNativeQuery(namedQuery);
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.TO_LIST);
		this.initQueryParamters(paramMap, query);
		return query.getResultList();
	}

	@Override
	public <T> List<T> queryListByNamedQuery(String namedQuery, Map<String, Object> paramMap, Class<T> targetClass) {
		EntityManager em = getEntityManager();
		Query query = em.createNamedQuery(namedQuery);
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(targetClass));
		this.initQueryParamters(paramMap, query);
		return (List<T>) query.getResultList();
	}

	@Override
	public List queryMapByNamedQuery(String namedQuery, Map<String, Object> paramMap) {
		EntityManager em = getEntityManager();
		Query query = em.createNativeQuery(namedQuery);
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		this.initQueryParamters(paramMap, query);
		return query.getResultList();
	}

	@Override
	public int exec(String sql, Map<String, Object> paramMap) {
		EntityManager em = getEntityManager();
		Query query = em.createNativeQuery(sql);
		this.initQueryParamters(paramMap, query);
		return query.executeUpdate();
	}

	@Override
	public Object querySingle(String sqlString, Map<String, Object> paramMap) {
		EntityManager em = getEntityManager();
		Query query = em.createNativeQuery(sqlString);
		this.initQueryParamters(paramMap, query);
		return query.getSingleResult();
	}

	@Override
	public List queryList(String sqlString, Map<String, Object> paramMap) {
		EntityManager em = getEntityManager();
		Query query = em.createNativeQuery(sqlString);
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.TO_LIST);
		this.initQueryParamters(paramMap, query);
		return query.getResultList();
	}

	@Override
	public List queryMap(String sqlString, Map<String, Object> paramMap) {
		EntityManager em = getEntityManager();
		Query query = em.createNativeQuery(sqlString);
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		this.initQueryParamters(paramMap, query);
		return query.getResultList();
	}

	@Override
	public <T> List<T> queryList(String sqlString, Map<String, Object> paramMap, Class<T> targetClass) {
		EntityManager em = getEntityManager();
		Query query = em.createNativeQuery(sqlString);
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(targetClass));
		this.initQueryParamters(paramMap, query);
		return (List<T>) query.getResultList();
	}
	
	private void initQueryParamters(Map<String, Object> paramMap, Query query) {
		if (paramMap != null) {
			for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
				query.setParameter(entry.getKey(), entry.getValue());
			}
		}
	}

	protected EntityManager getEntityManager() {
		return entityManager;
	}

}
